#include "Ship.h"
#include <string>
#include "../../common/lib/SDL_rotozoom.h"

Ship::Ship() {

	surfaceReference = NULL;
	goingBackwards = false;
	goingForward = false;
	turningLeft = false;
	turningRight = false;
	shooting = false;
	keyPressed = false;
	angle = 0.0;

}

Ship::Ship(ShipStatus* shipStatus) :
	WidgetMovimiento(shipStatus->getPosX(), shipStatus->getPosY(), parent) {

	//Informacion basica
	imagePath = shipStatus->getImagePath();
	rotationVelocity = shipStatus->getVelRotacion();
	maximumVelocity = shipStatus->getVelMax();
	propulsion = shipStatus->getPropultion();
	friction = shipStatus->getFriccion();
	bulletLifeTime = shipStatus->getDuracionBala();
	owner = shipStatus->getOwner();
	angle = shipStatus->getAngle();

	loadSurfaceImageFiles();

	parcel = getPosition();
	parcel.height = surfaceReference->h;
	parcel.width = surfaceReference->w;

	nextX = 0;
	nextY = 0;
	actualVelocity = 0;

	combustionEffect = false;
	goingBackwards = false;
	goingForward = false;
	turningLeft = false;
	turningRight = false;
	shooting = false;
	keyPressed = false;
}

Ship::Ship(std::string pathImage, float rotationVelocity, int maximumVelocity,
		int propultion, int friccion, int duracionBala, int posX, int posY,
		Widget *parent, std::string owner, int angle) :
	WidgetMovimiento(posX, posY, parent) {

	//Informacion basica
	this->imagePath = pathImage;
	this->rotationVelocity = rotationVelocity;
	this->maximumVelocity = maximumVelocity;
	this->propulsion = propultion;
	this->friction = friccion;
	this->bulletLifeTime = duracionBala;
	this->angle = angle;
	this->owner = owner;

	loadSurfaceImageFiles();

	parcel = getPosition();
	parcel.height = surfaceReference->h;
	parcel.width = surfaceReference->w;

	nextX = 0;
	nextY = 0;
	actualVelocity = 0;

	combustionEffect = false;
	goingBackwards = false;
	goingForward = false;
	turningLeft = false;
	turningRight = false;
	shooting = false;
	keyPressed = false;
}

void Ship::handleEvent(Event event) {
	/*std::stringstream owner;
	 owner << "owner: " << this->owner;

	 Logger::log("Ship", "handleEvent", &owner);*/

	if ((event.getSender() == this->owner) || duenoesinstancialocal) {

		if (event.getType() == UserEvent) {

			Logger::log("Ship", "handleEvent", "entro al handle del ship");

			if (event.getintData2() == KeyDown) {
				if (event.getEvent()->user.code == KeyPressed) {
					goingBackwards = true;
				} else if (event.getEvent()->user.code == KeyReleased) {
					goingBackwards = false;
				}
			}

			else if (event.getintData2() == KeyUp) {
				if (event.getEvent()->user.code == KeyPressed) {
					Logger::log("Ship", "handleEvent", "toma el evento");
					goingForward = true;
				} else if (event.getEvent()->user.code == KeyReleased) {
					goingForward = false;
				}
			}

			else if (event.getintData2() == KeyLeft) {
				if (event.getEvent()->user.code == KeyPressed) {
					turningLeft = true;
				} else if (event.getEvent()->user.code == KeyReleased) {
					turningLeft = false;
				}
			}

			else if (event.getintData2() == KeyRight) {
				if (event.getEvent()->user.code == KeyPressed) {
					turningRight = true;
				} else if (event.getEvent()->user.code == KeyReleased) {
					turningRight = false;
				}
			}

			else if (event.getintData2() == Space) {
				if (event.getEvent()->user.code == KeyPressed) {
					shooting = true;
				} else if (event.getEvent()->user.code == KeyReleased) {
					shooting = false;
				}
			}
		} else {

			//	keyState = event.getType();
			switch (event.getKey()) {
			case KeyDown:
				if (event.getType() == KeyPressed) {
					goingBackwards = true;
				} else if (event.getType() == KeyReleased) {
					goingBackwards = false;
				}
				keyPressed = false;
				break;
			case KeyUp:
				if (event.getType() == KeyPressed) {
					goingForward = true;
				} else if (event.getType() == KeyReleased) {
					goingForward = false;
				}
				keyPressed = false;
				break;
			case KeyLeft:
				if (event.getType() == KeyPressed) {
					turningLeft = true;
				} else if (event.getType() == KeyReleased) {
					turningLeft = false;
				}
				keyPressed = false;
				break;
			case KeyRight:
				if (event.getType() == KeyPressed) {
					turningRight = true;
				} else if (event.getType() == KeyReleased) {
					turningRight = false;
				}
				keyPressed = false;
				break;
			case Space:
				if ((event.getType() == KeyPressed) && (keyPressed == false)) {
					shooting = true;
					keyPressed = true;
				} else if ((keyPressed == true) && (event.getType()
						== KeyReleased)) {
					keyPressed = false;
					shooting = false;
				}
				break;
			default:
				break;
			}
		}

	}
}

void Ship::resolve() {
	//Timer to get seconds between frames
	if (!timer.is_started()) {
		timer.start();
	}

	float secsPerFrame = (timer.get_ticks() / 1000.0);

	if (turningLeft) {

		float angularRate = fmod(secsPerFrame, rotationVelocity)
				/ rotationVelocity;
		if ((angle + (360.0 * angularRate)) <= 359.0) {
			if (360.0 * angularRate >= 1) {
				angle += 360.0 * angularRate;
			} else
				angle++;
		} else if (360.0 * angularRate >= 1)
			angle = angle + (360.0 * angularRate) - 359.0;

	} else if (turningRight) {
		float angularRate = fmod(secsPerFrame, rotationVelocity)
				/ rotationVelocity;
		if ((angle - (360.0 * angularRate)) >= 0.0) {
			if (360.0 * angularRate >= 1) {
				angle -= 360.0 * angularRate;
			} else
				angle--;
		} else if (360.0 * angularRate >= 1)
			angle = angle - (360.0 * angularRate) + 359.0;

	}

	if (goingForward) {
		combustionEffect = !combustionEffect;

		if (actualVelocity + propulsion * secsPerFrame < maximumVelocity)
			actualVelocity = actualVelocity + propulsion * secsPerFrame;
		else
			actualVelocity = maximumVelocity;

		nextX = actualVelocity * cos(angle * (M_PI / 180.0)) * secsPerFrame;
		nextY = (-1.0) * actualVelocity * sin(angle * (M_PI / 180.0))
				* secsPerFrame;

	} else {
		if (combustionEffect)
			combustionEffect = false;

		actualVelocity = actualVelocity - friction * secsPerFrame;

		if (actualVelocity < 0)
			actualVelocity = 0;

		nextX = actualVelocity * cos(angle * (M_PI / 180.0)) * secsPerFrame;
		nextY = (-1.0) * actualVelocity * sin(angle * (M_PI / 180.0))
				* secsPerFrame;
	}

	parcel.posX += nextX;
	parcel.posY += nextY;

	if (combustionEffect) {
		surfaceReference = combustionShipSurface;
		combustionEffect = !combustionEffect;
	} else
		surfaceReference = shipSurface;

	timer.start();
}

void Ship::loadSurfaceImageFiles() {
	shipSurface = loadSurface(imagePath);
	if (shipSurface == NULL) {
		shipSurface = loadSurface(SH_DEFAULT_IMAGE);
	}
	//Retrieving combustion image file path
	std::string pathCombustionImage = imagePath.substr(0, imagePath.rfind('.'));
	std::string extension = imagePath.substr(imagePath.rfind('.'));

	pathCombustionImage.append("_fuego" + extension);
	combustionShipSurface = loadSurface(pathCombustionImage);
	if (combustionShipSurface == NULL)
		combustionShipSurface = loadSurface(SH_DEFAULT_IMAGE_COMBUSTION);

	//Setting transparent image color
	SDL_SetColorKey(shipSurface, SDL_SRCCOLORKEY, SDL_MapRGB(
			shipSurface->format, 0, 255, 255));

	//Setting transparent image color
	SDL_SetColorKey(combustionShipSurface, SDL_SRCCOLORKEY, SDL_MapRGB(
			combustionShipSurface->format, 0, 255, 255));

	surfaceReference = shipSurface;
}

int Ship::getBulletAngle() {
	return angle;
}

bool Ship::isShooting() {
	bool result = this->shooting;
	this->shooting = false;
	return result;
}

int Ship::getBulletLifeTime() {
	return bulletLifeTime;
}

Ship::~Ship() {
	SDL_FreeSurface(surfaceReference);
}

int Ship::getBulletX() {
	float angleInRadians = angle * (M_PI / 180.0);
	return parcel.posX + (parcel.height / 2) * cos(angleInRadians);
}

int Ship::getBulletY() {
	float angleInRadians = angle * (M_PI / 180.0);
	return parcel.posY - (parcel.height / 2) * sin(angleInRadians);
}

std::string Ship::getOwner() {
	return owner;
}

ShipStatus Ship::getShipStatus() {
	Parcel parcelAux;
	parcelAux = getPosition();

	return ShipStatus(owner, imagePath, rotationVelocity, maximumVelocity,
			propulsion, friction, bulletLifeTime, parcelAux.posX,
			parcelAux.posY);
}
